<?php

namespace ltcms\lib;

use  ltcms\error\ErrorException;

/**
 * 错误处理类
 */
class ErrorClass
{
    private static $_instance;
    protected $types=array(
        E_ERROR=>"error",
        E_USER_ERROR=>"error",
        E_WARNING=>"warning",
        E_USER_WARNING=>"warning",
        E_NOTICE=>"notice",
        E_USER_NOTICE=>"notice",
    );
    protected $registered=false;

    private function __construct(){}
    private function __clone(){ }

    /**
     * 获取类对象
     */
    public static  function getInstance(){
        if(!(self::$_instance instanceof self)){
            self::$_instance=new self();
        }
        return self::$_instance;
    }

    /**
     * 错误处理类
     * @param $name
     */
    function appError($errno,$errstr,$errfile,$errline)
    {
        $exception = new ErrorException($errno, $errstr, $errfile, $errline);
        if (error_reporting() & $errno) {
            $this->appException($exception);
        }
    }

    /**
     * 错误处理类
     * @param $name
     */
    function appException(\Throwable $exception)
    {
        $error=$this->report($exception);
        $logLevel=config("log.level",array());
        if($logLevel && in_array($error["type"],$logLevel)){
            $isAjax=request()->isAjax();
            ob_end_clean();
            if($isAjax){
                $result=apiResult(false,$error["message"],$error["code"]);
                $response=jsonResponse($result,$error["code"]);
                $response->send();
                exit;
            }else{
                $redirect_status=request()->server("REDIRECT_REDIRECT_STATUS");
                $redirect_path_info=request()->server("REDIRECT_PATH_INFO");
                if($redirect_status && $redirect_path_info){
                    //超时设置
                    echo "超时了";
                    exit;
                }else{
                    $class=strtolower(get_class($exception));
                    $http_exception_template=config("error.http_exception_template");
                    $custom_exception_template=config("error.{$class}");
                    $template=isset($http_exception_template[$error["code"]])?$http_exception_template[$error["code"]]:"error/index";
                    $custom_template=isset($custom_exception_template[$error["code"]])?$custom_exception_template[$error["code"]]:"";
                    if($custom_template){
                        $template=$custom_template;
                    }
                    if($error["code"] >=100 && $error["code"]<600){
                        $code=$error["code"];
                    }else{
                        $code=200;
                    }
                    $response=view($template,$error,$code);
                    $response->send();
                    exit;
                }
            }
        }
    }

    /**
     * 确定错误类型是否致命
     */
    protected function isFatal($type)
    {
        return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
    }

    /**
     * 记录错误
     * @param $exception
     * @return array
     */
    public function report($exception){
        $error=array();
        $error["time"]=date("Y-m-d H:i:s");
        $error["code"]=$exception->getCode();
        $error["type"]=isset($this->types[$error["code"]])?$this->types[$error["code"]]:"unknown";
        $error["message"]=$exception->getMessage();
        $error["file"]=$exception->getFile();
        $error["line"]=$exception->getLine();

        $type=config("log.report_type",array());
        if(in_array($error["type"],$type)){
            $errorFile=LTCMS_ROOT."/runtime/log/".date("Y-m-d").".log.exception";
            makeDir(dirname($errorFile));
            @file_put_contents($errorFile,toJsonEncode($error).PHP_EOL,FILE_APPEND);
        }
        return $error;
    }

    /**
     * 应用执行完毕
     */
    public function appShutdown(){
        if (!is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
            // 将错误信息托管至 ErrorException
            $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);
            $this->appException($exception);
        }
    }

    function register(){
        if(!$this->registered){
            $this->registered=true;
            error_reporting(E_ALL);
            set_error_handler(array(&$this,"appError"));
            set_exception_handler(array(&$this,"appException"));
            register_shutdown_function([$this, 'appShutdown']);
        }
    }
}